#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>

#include "sqlite3.h"
#include "cJSON.h"
#include "mosquitto.h"
#include "iniparser.h"
#include "logger.h"
#include "sqlite_select.h"
#include "cloud_ini.h"
#include "sqlite.h"
#include "get_cJSON.h"

#define  KEEP_LIVE   60
#define  PORT        1883

void *thread_pub(void *args);	
int pthread_ini(pthread_attr_t  *thread_attr);
void on_connect_callback(struct mosquitto *mosq, void *obj, int rv);
void on_publish_callback(struct mosquitto *mosq, void *obj, int mid);
void on_disconnect_callback(struct mosquitto *mosq, void *obj, int rc);

static int running=1;

void print_usage(char *progname)
{
	printf("%s usage: \n", progname);
	printf("-d(--deamon): Running in deamon\n");
	printf("-i(--ini_file): Choose ini_file to connect three cloud\n");
	printf("-h(--help): Display this information\n");

	return ;
}

int main (int argc,char ** argv)
{
	int                     rv = -1;
	int                     go_deam = 0;
	int                     opt;
	char                    *progname = NULL;
	char                    *ini_file = NULL;

	pthread_attr_t          thread_attr;
	pthread_t               tid;
	cloud_ini_t             cloud_ini;

	struct mosquitto        *mosq;
	struct option           opts[] = {
		{"daemon", required_argument, NULL, 'd'},
		{"ini_file", required_argument, NULL, 'i'},
		{"help", no_argument, NULL, 'h'},
		{NULL, 0, NULL, 0}
	};

	while((opt = getopt_long(argc, argv, "d:i:h", opts, NULL)) != -1)
	{
		switch(opt)
		{
			case 'd':
				go_deam = atoi(optarg);
				break;

			case 'i':
				ini_file = optarg;
				break;

			case 'h':
				print_usage(argv[0]);
				return 0;

			default:
				printf("input failure!\n");
				break;
		}
	}

 	if(!ini_file)
	{
		print_usage(argv[0]);
		return 0;
	}
	printf("ini_file:%s\n", ini_file);


	if(go_deam)
	{
		if(daemon(0,0)<0)
		{
			printf("daemon failure:%s\n",strerror(errno));
			return -1;
		}
	}
	printf("ini_file[95]:%s\n", ini_file);
	
	if(logger_init("mqtt_pub.log",LOG_LEVEL_DEBUG)<0)
	{
		fprintf(stderr,"initial logger system failure\n");
		goto clean;
	}

	memset(&cloud_ini,0,sizeof(cloud_ini));

	rv=cloud_ini_get(ini_file, &cloud_ini);
	if(rv)
	{
		log_error("get cloud_ini failure:%s\n",strerror(errno));
		goto clean;
	}
	log_info("get cloud_ini successful!\n");

	if(pthread_ini(&thread_attr))
	{
		log_error("pthread_ini failure:%s\n",strerror(errno));
		goto clean;
	}
	log_info("pthread_ini successful!\n");

	if(pthread_create(&tid, &thread_attr, thread_pub, &cloud_ini))
	{
		log_error("pthread_create pub failure:%s\n",strerror(errno));
		goto clean;
	}
	log_info("pthread_create thread_pub successful!\n");
	
clean:
	pthread_attr_destroy(&thread_attr);
	pthread_join(tid, NULL);
	logger_term();
	return 0;
}

int pthread_ini(pthread_attr_t  *thread_attr)
{
	log_info("Start pthread_ini!\n");

	if( pthread_attr_init(thread_attr))
	{
		log_error("pthread_attr_init failure:%s\n",strerror(errno));
		goto clean;
	}

	if(pthread_attr_setstacksize(thread_attr, 120*1024))
	{
		log_error("pthread_attr_setstacksize failure:%s\n",strerror(errno));
		goto clean;
	}

/*	if(pthread_attr_setdetachstate(thread_attr, PTHREAD_CREATE_DETACHED))
	{
		log_error("pthread_attr_setdetachstate failure:%s\n",strerror(errno));
		goto clean;
	}
*/
	log_info("Pthread_ini return !\n");

clean:
	pthread_attr_destroy(thread_attr);
	return 0;
}

void *thread_pub(void *args)	
{
	int                  rv=-1;
	char                 *out = NULL;

	struct              mosquitto  *mosq;

	cloud_ini_t *cloud_ini =(cloud_ini_t*)args;

	log_info("thread_pub[pub] start!\n");

	if(!args)
	{
		log_error("get args thread_pub failure:%s\n", strerror(errno));
		goto clean;
	}
	log_info("get args successful!\n");

	rv=mosquitto_lib_init();
	if(rv != MOSQ_ERR_SUCCESS)
	{
		log_error("mos_lib failure:%s\n", strerror(errno));
		goto clean;
	}
	log_info("mos_lib sucessful!\n");

	mosq=mosquitto_new(cloud_ini->clientid, true, NULL);
	if(NULL == mosq)
	{
		log_error("Create new client failure:%s\n", strerror(errno));
		goto clean;
	}
	log_info("create new client!\n");

	mosquitto_connect_callback_set(mosq, on_connect_callback);
	mosquitto_publish_callback_set(mosq, on_publish_callback);
	mosquitto_disconnect_callback_set(mosq, on_disconnect_callback);

	rv=mosquitto_username_pw_set(mosq, cloud_ini->username, cloud_ini->password);
	if(rv != MOSQ_ERR_SUCCESS)
	{
		log_error("user_pw_set failure:%s\n", strerror(errno));
		goto clean;
	}
	log_info("user_pw_set sucessful!\n");

	rv=mosquitto_connect(mosq, cloud_ini->HOST,PORT, KEEP_LIVE);
	if(rv != MOSQ_ERR_SUCCESS)
	{
		log_error("Connect to server failure:%s\n", strerror(errno));
		goto clean;
	}
	log_info("Sent connect successful!\n");

	rv=mosquitto_loop_start(mosq);
	if(rv != MOSQ_ERR_SUCCESS)
	{
		printf("Connect to server failure:%s\n", strerror(errno));
		log_error("Connect to server failure:%s\n", strerror(errno));
		goto clean;
	}
	log_info("loop successful!\n");
	printf("loop successful!\n");

	while(1)
	{
		rv=get_cJSON(&out);
		if(rv)
		{
			log_error("get cJSON failure:%s\n", strerror(errno));
			goto clean;
		}
		printf("out[239]:%s\n", out);

		rv=mosquitto_publish(mosq, NULL, cloud_ini->topic_push, strlen(out), out, 0, false);	
		if(rv!=MOSQ_ERR_SUCCESS)
		{
			log_error("Publish[202]  failure:%s\n", strerror(errno));
			mosquitto_disconnect(mosq);
		}
		log_info("Publish[205] successful!\n");
		sleep(3);
	}
	
clean:
	mosquitto_lib_cleanup();
	mosquitto_destroy(mosq);
	return NULL;
}

void on_connect_callback(struct mosquitto *mosq, void *obj, int rv)
{
	log_info("Call the function:on_connect_callback!\n");
	if(rv)
	{
		log_error("Server reserve message failure:%s\n", strerror(errno));
		mosquitto_disconnect(mosq);
	}
	log_info("Connect successful!\n");
}

void on_publish_callback(struct mosquitto *mosq, void *obj, int mid)
{
	char     ID_select[12]={};
	char     time_select[68]={};
	float    temp_select;
	struct   cloud_ini_s  cloud_ini;

	log_info("Call the function:on_publish_callback!\n");
	if(!mid)
	{
		log_error("Server reserve message failure:%s\n", strerror(errno));

		temp_select=sqlite(cloud_ini.sqlite_topic,ID_select,time_select, 1, 0);
		if(!temp_select)
		{
			log_error("insert failure:%s\n",strerror(errno));
			return;
		}
		log_info("insert ok\n");
		mosquitto_disconnect(mosq);
	}
	log_info("Publish[335] successful!\n");

}

void on_disconnect_callback(struct mosquitto *mosq, void *obj, int rc)
{
	int                  rv = -1;
	struct cloud_ini_s   cloud_ini;

	log_info("Call the function:on_disconnect_callback!\n");
	if(rc)
	{
		log_error("Connect failure:%s\n", strerror(errno));
		rv=mosquitto_connect(mosq, cloud_ini.HOST,PORT, KEEP_LIVE);
		if(rv!=MOSQ_ERR_SUCCESS)
		{
			log_error("connect[dis] failure:%s\n",strerror(errno));
			return;
		}
	}
}
